/*
Copyright 2008, 2009 Joonas Lehtolahti

This file is part of Openfire-C.

Openfire-C is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Openfire-C is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Openfire-C.  If not, see <http://www.gnu.org/licenses/>.
*/

int XfireAnalyze_hVideos(XFINST inst, struct XfirePacket *packet) {
	/* List of videos for a friend
	 * http://xfireplus.com/xfwiki/index.php/Packet_b6_00
	 *
	 * Single list callback way!
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT unsigned int, LinkedList*
	#define _XFABP *userid_value, video_list
	
	unsigned int *userid_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x01));
	LinkedList *index_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x93));
	LinkedList *title_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x94));
	LinkedList *size_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x55));
	LinkedList *res_x_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x95));
	LinkedList *res_y_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x96));
	LinkedList *frames_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x97));
	LinkedList *fps_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x98));
	LinkedList *gameid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x21));
	LinkedList *time_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x50));
	LinkedList *desc_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x54));
	
	LinkedList *video_list = LLcreate();
	
	if (userid_value && index_list && title_list && size_list && res_x_list &&
		res_y_list && frames_list && fps_list && gameid_list && time_list &&
		desc_list && video_list) {
		if (index_list->nodes == title_list->nodes && title_list->nodes == size_list->nodes &&
			size_list->nodes == res_x_list->nodes && res_x_list->nodes == res_y_list->nodes &&
			res_y_list->nodes == frames_list->nodes && frames_list->nodes == fps_list->nodes &&
			fps_list->nodes == gameid_list->nodes && gameid_list->nodes == time_list->nodes &&
			time_list->nodes == desc_list->nodes) {
			
			ListNode *index_node = index_list->first;
			ListNode *title_node = title_list->first;
			ListNode *size_node = size_list->first;
			ListNode *res_x_node = res_x_list->first;
			ListNode *res_y_node = res_y_list->first;
			ListNode *frames_node = frames_list->first;
			ListNode *fps_node = fps_list->first;
			ListNode *gameid_node = gameid_list->first;
			ListNode *time_node = time_list->first;
			ListNode *desc_node = desc_list->first;
			
			struct XfVideoInfo *xfv;
			while (index_node) {
				xfv = XfireVideoInfo();
				xfv->index = *(unsigned int*)index_node->x;
				xfv->title = n0scopy((non0string*)title_node->x);
				xfv->description = n0scopy((non0string*)desc_node->x);
				xfv->filesize = *(unsigned int*)size_node->x;
				xfv->res_x = *(unsigned int*)res_x_node->x;
				xfv->res_y = *(unsigned int*)res_y_node->x;
				xfv->frames = *(unsigned int*)frames_node->x;
				xfv->fps = *(unsigned int*)fps_node->x;
				xfv->gameid = *(unsigned int*)gameid_node->x;
				xfv->timestamp = *(unsigned int*)time_node->x;
				
				LLaddLast(video_list, xfv);
				
				NEXT_NODE(index_node);
				NEXT_NODE(title_node);
				NEXT_NODE(size_node);
				NEXT_NODE(res_x_node);
				NEXT_NODE(res_y_node);
				NEXT_NODE(frames_node);
				NEXT_NODE(fps_node);
				NEXT_NODE(gameid_node);
				NEXT_NODE(time_node);
				NEXT_NODE(desc_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			
			/* internal handling */
			if (retval & XFIH_HANDLED) {
				struct XfFriend *xff = XfireInst_FindUserByUserid(inst, *userid_value);
				
				if (xff) {
					ListNode *video_node = video_list->first;
					
					/* Clear the old video list */
					LLdelete(xff->extdata->videos, (FREEFUNC*)FreeXfireVideoInfo);
					xff->extdata->videos = LLcreate();
					
					while (video_node) {
						LLaddLast(xff->extdata->videos, video_node->x);
						
						NEXT_NODE(video_node);
					}
				}
				else {
					/* We don't know that user? */
					retval |= XFIH_NONFATAL;
				}
			}
		}
		else {
			/* Different length of lists */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(video_list, NULL);
	LLdelete(index_list, NULL);
	LLdelete(title_list, NULL);
	LLdelete(size_list, NULL);
	LLdelete(res_x_list, NULL);
	LLdelete(res_y_list, NULL);
	LLdelete(frames_list, NULL);
	LLdelete(fps_list, NULL);
	LLdelete(gameid_list, NULL);
	LLdelete(time_list, NULL);
	LLdelete(desc_list, NULL);
	
	return retval;
}

int XfireAnalyze_hMyVideos(XFINST inst, struct XfirePacket *packet) {
	/* List of videos for the client itself
	 * http://xfireplus.com/xfwiki/index.php/Packet_b3_00
	 *
	 * Single list callback way!
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*
	#define _XFABP video_list
	
	LinkedList *index_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x93));
	LinkedList *title_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x94));
	LinkedList *size_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x55));
	LinkedList *res_x_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x95));
	LinkedList *res_y_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x96));
	LinkedList *frames_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x97));
	LinkedList *fps_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x98));
	LinkedList *gameid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x21));
	LinkedList *time_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x50));
	LinkedList *desc_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x54));
	
	LinkedList *video_list = LLcreate();
	
	if (index_list && title_list && size_list && res_x_list && res_y_list &&
		frames_list && fps_list && gameid_list && time_list && desc_list &&
		video_list) {
		if (index_list->nodes == title_list->nodes && title_list->nodes == size_list->nodes &&
			size_list->nodes == res_x_list->nodes && res_x_list->nodes == res_y_list->nodes &&
			res_y_list->nodes == frames_list->nodes && frames_list->nodes == fps_list->nodes &&
			fps_list->nodes == gameid_list->nodes && gameid_list->nodes == time_list->nodes &&
			time_list->nodes == desc_list->nodes) {
			
			ListNode *index_node = index_list->first;
			ListNode *title_node = title_list->first;
			ListNode *size_node = size_list->first;
			ListNode *res_x_node = res_x_list->first;
			ListNode *res_y_node = res_y_list->first;
			ListNode *frames_node = frames_list->first;
			ListNode *fps_node = fps_list->first;
			ListNode *gameid_node = gameid_list->first;
			ListNode *time_node = time_list->first;
			ListNode *desc_node = desc_list->first;
			
			struct XfVideoInfo *xfv;
			while (index_node) {
				xfv = XfireVideoInfo();
				xfv->index = *(unsigned int*)index_node->x;
				xfv->title = n0scopy((non0string*)title_node->x);
				xfv->description = n0scopy((non0string*)desc_node->x);
				xfv->filesize = *(unsigned int*)size_node->x;
				xfv->res_x = *(unsigned int*)res_x_node->x;
				xfv->res_y = *(unsigned int*)res_y_node->x;
				xfv->frames = *(unsigned int*)frames_node->x;
				xfv->fps = *(unsigned int*)fps_node->x;
				xfv->gameid = *(unsigned int*)gameid_node->x;
				xfv->timestamp = *(unsigned int*)time_node->x;
				
				LLaddLast(video_list, xfv);
				
				NEXT_NODE(index_node);
				NEXT_NODE(title_node);
				NEXT_NODE(size_node);
				NEXT_NODE(res_x_node);
				NEXT_NODE(res_y_node);
				NEXT_NODE(frames_node);
				NEXT_NODE(fps_node);
				NEXT_NODE(gameid_node);
				NEXT_NODE(time_node);
				NEXT_NODE(desc_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			
			/* internal handling */
			if (retval & XFIH_HANDLED) {
				struct XfFriend *xff = inst->self;
				
				if (xff) {
					ListNode *video_node = video_list->first;
					
					while (video_node) {
						LLaddLast(xff->extdata->videos, video_node->x);
						
						NEXT_NODE(video_node);
					}
				}
				else {
					/* Self not found?! */
					retval |= XFIH_NONFATAL;
				}
			}
		}
		else {
			/* Different length of lists */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(video_list, NULL);
	LLdelete(index_list, NULL);
	LLdelete(title_list, NULL);
	LLdelete(size_list, NULL);
	LLdelete(res_x_list, NULL);
	LLdelete(res_y_list, NULL);
	LLdelete(frames_list, NULL);
	LLdelete(fps_list, NULL);
	LLdelete(gameid_list, NULL);
	LLdelete(time_list, NULL);
	LLdelete(desc_list, NULL);
	
	return retval;
}

int XfireAnalyze_hLiveVideo(XFINST inst, struct XfirePacket *packet) {
	/* A friend is broadcasting a live video or stopped the broadcast
	 * http://xfireplus.com/xfwiki/index.php/Packet_b8_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT struct XfFriend*, struct XfBroadcast*
	#define _XFABP user, broadcast
	
	non0string *sid_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\x03));
	non0string *title_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\x94));
	non0string *desc_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\x54));
	non0string *dyynoid_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\x9e));
	non0string *image_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\xa3));
	non0string *ip_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\x9f));
	non0string *watchers_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\xa0));
	non0string *port_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\xa1));
	/* TODO: non0string *???_value = XfirePacketGetStringAttribute(packet, SHORT_ATTRIBUTE(\xa2)); */
	unsigned int *friends_only_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\xa4));
	
	if (sid_value && title_value && desc_value && dyynoid_value &&
		image_value && ip_value && watchers_value && port_value) {
		
		struct XfFriend *user = XfireInst_FindUserBySid(inst, sid_value);
		struct XfBroadcast *broadcast = XfireBroadcast();
		
		broadcast->title = n0scopy(title_value);
		broadcast->description = n0scopy(desc_value);
		broadcast->sessionid = n0scopy(dyynoid_value);
		broadcast->sessionimage = n0scopy(image_value);
		broadcast->ipaddress = n0scopy(ip_value);
		broadcast->watchers = n0scopy(watchers_value);
		broadcast->ipport = n0scopy(port_value);
		broadcast->friends_only = *friends_only_value;
		
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* internal handling */
		if (retval & XFIH_HANDLED) {
			if (user) {
				FreeXfireBroadcast(user->extdata->live_video);
				user->extdata->live_video = broadcast;
			}
			else {
				/* Unknown user? */
				retval |= XFIH_NONFATAL;
			}
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	/* Nothing to clear up */
	
	return retval;
}
